package tr.edu.metu.is.mega.client.core;

import tr.edu.metu.is.mega.client.LoginDialog;
import tr.edu.metu.is.mega.client.LoginParameters;
import tr.edu.metu.is.mega.client.core.event.SelectionEventBus;
import tr.edu.metu.is.mega.client.resource.MEGAResources;
import tr.edu.metu.is.mega.client.service.GwtAuthenticationService;
import tr.edu.metu.is.mega.client.service.GwtAuthenticationServiceAsync;
import tr.edu.metu.is.mega.common.dto.UserDTO;

import com.extjs.gxt.ui.client.widget.Info;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.layout.CenterLayout;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.RootPanel;

/**
 * Singleton authentication manager.
 * 
 */
public final class AuthUtils {

    private static AuthUtils instance = null;

    private final GwtAuthenticationServiceAsync authenticationService;

    /**
     * Hidden constructor.
     */
    private AuthUtils() {
        authenticationService = GwtAuthenticationService.Util.getInstance();
    }

    /**
     * Returns singleton instance of this.
     * 
     * @return singleton instance of this
     */
    public static AuthUtils getInstance() {
        if (instance == null) {
            instance = new AuthUtils();
        }
        return instance;
    }

    /**
     * Logs user in.
     * 
     * @param callback login callback
     */
    public void login(final LoginCallbackHandler callback) {
        authenticationService.getFromSession(new AsyncCallback<UserDTO>() {

            @Override
            public void onSuccess(UserDTO result) {
                if (result == null) {
                    loginLayout(callback);
                } else {
                    callback.loggedIn(result);
                }

            }

            private void loginLayout(final LoginCallbackHandler callback) {
                LoginDialog dialog = new LoginDialog();
                RootPanel rootPanel = RootPanel.get("root");
                if (rootPanel.getWidgetCount() > 0) {
                    rootPanel.remove(0);
                }
                LayoutContainer container = new LayoutContainer();
                container.setLayout(new CenterLayout());
                container.setSize(1024, 768);
                container.add(dialog);
                rootPanel.add(container);
                dialog.login(new DialogCallbackAdapter<LoginParameters>() {

                    @Override
                    public void onOk(LoginParameters params) {
                        doLogin(callback, params);
                    }

                });
            }

            @Override
            public void onFailure(Throwable caught) {
                loginLayout(callback);
            }
        });
    }

    /**
     * Handles login operation.
     * 
     * @param callback login callback
     * @param params login parameters
     */
    protected void doLogin(final LoginCallbackHandler callback, LoginParameters params) {
        authenticationService.login(params.getUserID(), params.getPassword(), new AsyncCallback<UserDTO>() {

            @Override
            public void onSuccess(UserDTO loggedInUser) {
                if (loggedInUser == null) {
                    MessageBox.alert(MEGAResources.RESOURCEBUNDLE.alertInvaidInfo(), MEGAResources.RESOURCEBUNDLE.alertInvaidInfo(), null);
                    login(callback);
                    return;
                }
                callback.loggedIn(loggedInUser);
            }

            @Override
            public void onFailure(Throwable caught) {
                MessageBox.alert(MEGAResources.RESOURCEBUNDLE.alertInvaidInfo(), MEGAResources.RESOURCEBUNDLE.alertLoginFailed(), null);
                login(callback);
            }
        });
    }

    /**
     * Logs user out.
     */
    public void logout() {
        authenticationService.logout(new AsyncCallback<Void>() {

            @Override
            public void onFailure(Throwable caught) {
            }

            @Override
            public void onSuccess(Void result) {
                Info.display("", MEGAResources.RESOURCEBUNDLE.alertLogoutSuccessull());
            }
        });
    }

    /**
     * Returns current logged in user.
     */
    public void getCurrentUser(final QueryCallback<UserDTO> callback) {
        authenticationService.getCurrentUser(new AsyncCallback<UserDTO>() {

            @Override
            public void onFailure(Throwable caught) {
                MessageBox.alert(MEGAResources.RESOURCEBUNDLE.alertInvaidInfo(), MEGAResources.RESOURCEBUNDLE.alertUserInfoFetchError(), null);
            }

            @Override
            public void onSuccess(UserDTO result) {
                callback.onQueryResult(result);
            }

        });
    }

    /**
     * Updates current logged in user.
     * 
     * @param user updated user.
     */
    public void updateCurrentUser(UserDTO user, final QueryCallback<Void> callback) {
        SelectionEventBus.getInstance().fireEvent(this, user);
        authenticationService.updateCurrentUser(user, new AsyncCallback<Void>() {

            @Override
            public void onFailure(Throwable caught) {
                MessageBox.alert(MEGAResources.RESOURCEBUNDLE.alertInvaidInfo(), MEGAResources.RESOURCEBUNDLE.alertUserInfoFetchError(), null);
            }

            @Override
            public void onSuccess(Void result) {
                callback.onQueryResult(result);
            }
        });
    }

}
